﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Web;
using System.Web.Routing;
using System.Web.Mvc;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Text.RegularExpressions;
using System.Globalization;
using Vit.Web.Models;
using Vit.Common.Extensions;

namespace Vit.Web.Services
{
    public class SiteService : ISiteService
    {
        private const string SitesRootPath = "~/Sites/";
        private const string ConfigurationFile = "~/Configuration/siteMappings.config";
        private List<WebSite> sites;

        #region ISiteService Members

        public IEnumerable<WebSite> GetSites()
        {
            if (sites != null)
                return sites;

            XDocument doc = XDocument.Load(HttpContext.Current.Server.MapPath(ConfigurationFile));

            sites = new List<WebSite>();
            DirectoryInfo dir = new DirectoryInfo(HttpContext.Current.Server.MapPath(SitesRootPath));
            foreach (DirectoryInfo sd in dir.GetDirectories())
            {
                XElement siteEle = doc.Root.XPathSelectElement(string.Format("site[@name='{0}']", sd.Name));
                if (siteEle == null)
                    continue;

                WebSite site = new WebSite();
                site.Name = sd.Name;
                site.DisplayName = site.Name;
                site.Description = site.Name;

                // site paths
                site.RootPath = VirtualPathUtility.Combine(SitesRootPath, sd.Name + "/");
                site.UserFilesPath = siteEle.AttributeValue("userFiles", null) ?? HttpContext.Current.Server.MapPath(VirtualPathUtility.Combine(site.RootPath, "UserFiles/"));

                site.PageTitleSeparator = siteEle.AttributeValue("pageTitleSeparator", "-");
                site.FavIconUrl = siteEle.AttributeValue("favIcon", null);
                site.DefaultGravatar = siteEle.AttributeValue("gravatar", null);

                // get site supported locale info
                List<Locale> locs = new List<Locale>();
                foreach (var l in siteEle.Element("locales").Elements("locale"))
                {
                    Locale loc = new Locale();
                    loc.Name = l.Attribute("name").Value;
                    loc.Language = l.AttributeValue("language", loc.Name);
                    loc.Culture = l.AttributeValue("culture", loc.Name);
                    loc.TimeZoneOffset = l.AttributeValue<double>("timezone", 0.0);
                    locs.Add(loc);
                }
                site.SupportLocales = locs;
                site.DefaultLocale = site.SupportLocales.First(o=>o.Name == siteEle.Attribute("defaultLocale").Value);

                // get mapping domain info
                List<MappingDomain> mappingDomains = new List<MappingDomain>();
                foreach (var d in siteEle.Element("domains").Elements("mapping"))
                {
                    MappingDomain dm = new MappingDomain();
                    dm.DomainPattern = d.Value;
                    dm.Locale = site.SupportLocales.FirstOrDefault(o => o.Name == d.AttributeValue("locale", site.DefaultLocale.Name));
                    mappingDomains.Add(dm);
                }
                site.MappingDomains = mappingDomains;

                // get themes
                List<Theme> themes = new List<Theme>();
                string themePath = VirtualPathUtility.Combine(site.RootPath, "Themes/"); 
                DirectoryInfo themeDir = new DirectoryInfo(HttpContext.Current.Server.MapPath(themePath));
                foreach (DirectoryInfo td in themeDir.GetDirectories())
                {
                    Theme theme = new Theme();
                    theme.Name = td.Name;
                    theme.Path = VirtualPathUtility.Combine(themePath, td.Name);

                    DirectoryInfo skinDir = td.GetDirectories("Skins", SearchOption.TopDirectoryOnly).FirstOrDefault();
                    if (skinDir != null)
                    {
                        List<Skin> skins = new List<Skin>();
                        foreach (FileInfo fi in skinDir.GetFiles("*.ascx"))
                        {
                            Skin sk = new Skin();
                            sk.Name = fi.Name.Replace(fi.Extension, "");
                            sk.Path = VirtualPathUtility.Combine(themePath, "Skins/" + fi.Name);
                            skins.Add(sk);
                        }
                        theme.Skins = skins;
                    }

                    List<Layout> layouts = new List<Layout>();
                    foreach (FileInfo fi in themeDir.GetFiles("*.ascx"))
                    {
                        Layout ly = new Layout();
                        ly.Name = fi.Name.Replace(fi.Extension, "");
                        ly.Path = VirtualPathUtility.Combine(themePath, fi.Name);
                        layouts.Add(ly);
                    }
                    theme.Layouts = layouts;

                    themes.Add(theme);
                }
                site.Themes = themes;
                site.DefaultTheme = site.Themes.First(o => o.Name == siteEle.AttributeValue("defaultTheme", "Default"));

                // get pages info
                List<WebPage> pages = new List<WebPage>();
                string pagePath = VirtualPathUtility.Combine(site.RootPath, "Pages/");
                DirectoryInfo pageDir = new DirectoryInfo(HttpContext.Current.Server.MapPath(pagePath));
                foreach (FileInfo file in pageDir.GetFiles("*.aspx"))
                {
                    if (file.Name.EndsWith(".design.aspx"))
                        continue;
                    WebPage page = new WebPage();
                    page.Name = file.Name.Replace(file.Extension, "");
                    page.Path = VirtualPathUtility.Combine(pagePath, file.Name);
                    page.WebSite = site;
                    pages.Add(page);
                }

                site.Pages = pages;
                site.HomePage = site.Pages.First(o => o.Name == siteEle.AttributeValue("homePage", "Index"));
                site.MissingPage = site.Pages.First(o => o.Name == siteEle.AttributeValue("missingPage", "Missing"));
                site.DialogPage = site.Pages.First(o => o.Name == siteEle.AttributeValue("dialogPage", "Dialog"));

                // get menu info
                List<Menu> menus = new List<Menu>();
                string menuPath = VirtualPathUtility.Combine(site.RootPath, "Menu/");
                DirectoryInfo menuDir = new DirectoryInfo(HttpContext.Current.Server.MapPath(menuPath));
                foreach (FileInfo file in menuDir.GetFiles("*.xml"))
                {
                    Menu menu = new Menu();
                    menu.Name = file.Name.Replace(file.Extension, "");
                    menu.Path = VirtualPathUtility.Combine(menuPath, file.Name);
                    menus.Add(menu);
                }

                site.Menu = menus;

                sites.Add(site);
            }

            return sites;
        }

        public WebSite GetSite(string name)
        {
            return GetSites().FirstOrDefault(o => o.Name == name);
        }

        public bool GetMappingSite(string url, out WebSite site)
        {
            site = null;
            foreach (WebSite s in GetSites())
            {
                if (s.MappingDomains != null)
                {
                    foreach (MappingDomain md in s.MappingDomains)
                    {
                        if (Regex.IsMatch(url, md.DomainPattern, RegexOptions.IgnoreCase))
                        {
                            site = s;
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        public IHttpHandler GetPageHanlder(RequestContext requestContext)
        {
            throw new NotImplementedException();
        }

        public WebSite GetCurrentSite()
        {
            return HttpContext.Current.Items["site"] as WebSite;
        }

        #endregion
    }
}
